﻿using GylCSharpUtils.Common.Utils;
using GylCSharpUtils.GSerializer.Abstract;
using System;
using System.Reflection;
using RT = GylCSharpUtils.Common.Utils.ReflectionTool;

namespace GylCSharpUtils.GSerializer.Template {
    public class GSTFieldInfo : IComparable{
        /// <summary>
        /// 字段名称
        /// </summary>
        public string Name { get; private set; }
        /// <summary>
        /// 字段Value类型
        /// </summary>
        public Type FieldType { get; private set; }
        /// <summary>
        /// 字段类型的全名
        /// </summary>
        public string FieldTypeFullName { get; private set; }
        /// <summary>
        /// 属性模板的序号
        /// </summary>
        public ushort TemplateIndex { get; private set; }
        /// <summary>
        /// 字段标志,2为二进制数 0值类型属性 1引用类型属性 2值类型字段 3引用类型字段
        /// </summary>
        public byte Flag { get; private set; }
        /// <summary>
        /// 是否为C#中的Field
        /// </summary>
        public bool IsField { get; private set; }
        /// <summary>
        /// 字段是否为值类型
        /// </summary>
        public bool IsValueType { get; private set; }

        /// <summary>
        /// 字段值的Setter
        /// </summary>
        public Action<object,object> Setter { get; private set; }
        /// <summary>
        /// 字段值的Getter
        /// </summary>
        public Func<object,object> Getter { get; private set; }

        public GSTFieldInfo(ushort templateIndex, PropertyInfo info) {
            SetProps(info.Name, info.PropertyType,templateIndex, true,
                RT.PropGetDelegate(info),
                RT.PropSetDelegate(info));

        }

        public GSTFieldInfo(ushort templateIndex, FieldInfo info) {
            SetProps(info.Name, info.FieldType,templateIndex, true, 
                RT.FieldGetDelegate(info), 
                RT.FieldSetDelegate(info));
        }

        public GSTFieldInfo(GSTFieldInfo info) {
            SetProps(info.Name, info.FieldType, info.TemplateIndex,info.IsField, info.Getter, info.Setter);
        }

        private void SetProps(string fieldName, Type fieldType, ushort templateindex,bool isField,Func<object, object> getter, Action<object, object> setter) {
            Name = fieldName;
            FieldType = fieldType;
            FieldTypeFullName = AGSerializer.GetTypeName(fieldType);
            TemplateIndex = templateindex;
            IsValueType = fieldType.IsValueType;
            IsField = isField;
            CalcFlag();
            Getter = getter;
            Setter = setter;
        }
        private byte CalcFlag() {
            byte flag = 0;
            if(!IsValueType) flag |= 0b01;
            if(IsField) flag |= 0b10;
            return flag;
        }

        public GSTFieldInfo(string name, Type type, bool isField) {
            Name = name;
            this.FieldType = type;
            Flag = type.IsValueType ? (byte)0b00 : (byte)0b01;
            if(isField) {
                Flag |= 0b10;
            }
        }

        public int CompareTo(object obj) {
            var info = (GSTFieldInfo)obj;
            return string.Compare(Name, info.Name);
        }

    }
}
